package com.yunshang.shoppingmall.common.weixin;

import com.yunshang.shoppingmall.entity.BillOrder;
import com.yunshang.shoppingmall.entity.Order;
import com.yunshang.shoppingmall.entity.PayOrder;
import javafx.scene.web.WebView;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
public class WeChat {
    public static String siteSurl="http://www.ycsqd.com";
    public static String appid="wxe3d0cfe6f19eb554";
    public static String appsecret="63c7edfdeff1688b24829356346fcd3c";
    public static String mch_id="1516579771";
    public static String paykey="1a3n2e84v916b4v357b5fvf29n9f6f1v";
    public static String siteName="新零售微店";

    //保存订单状态
    public static Map<String, PayOrder> orderData = new HashMap<>();

    //下单地址
    public static String DOWN_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    //回调地址
     public static String NOTIFY_URL = "http://www.ycsqd.com/API/Weixin/OrderURL";
    //public static String NOTIFY_URL = "http://weixin1.ycsqd.com/API/Weixin/OrderURL";

    //订单查询
    public static String ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";

    //下载对账单
    public static String BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";

    /**
     * 获取支付所需签名
     *
     * @param
     * @param key
     * @return
     * @throws Exception
     */
    public static String getPayCustomSign(Map map, String key) throws Exception {
        String bizString = FormatBizQueryParaMap(map, false);
        return sign(bizString, key);
    }

    /**
     * 进行字典排序
     *
     * @param paraMap
     * @param urlencode
     * @return
     * @throws Exception
     */
    public static String FormatBizQueryParaMap(Map paraMap, boolean urlencode) throws Exception {
        String sf = "";

        try {
            List<Map.Entry> infoIds = new ArrayList<Map.Entry>(paraMap.entrySet());
            Collections.sort(infoIds, new Comparator<Map.Entry>() {
                public int compare(Map.Entry o1, Map.Entry o2) {
                    return (o1.getKey().toString().compareTo(o2.getKey().toString()));
                }
            });
            for (int i = 0; i < infoIds.size(); i++) {
                Map.Entry entryItem = infoIds.get(i);
                if (entryItem.getKey() != "") {
                    String key = (String) entryItem.getKey();
                    String value = (String) entryItem.getValue();
                    if (urlencode) {
                        value = URLEncoder.encode(value, "utf-8");
                    }
                    sf += key + "=" + value + "&";
                }
            }
            if (sf.isEmpty() == false) {
                sf = sf.substring(0, sf.length() - 1);
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }

        return sf;
    }

    /**
     * 生成 签名
     *
     * @param content
     * @param key
     * @return
     */
    public static String sign(String content, String key) {
        String signStr = content + "&key=" + key;
        return Md5.MD5(signStr).toUpperCase();
    }


    /**
     * map 转 xml
     *
     * @param map
     * @return
     */
    public static String mapToXml(Map<String, String> map) {
        StringBuffer sf = new StringBuffer("<xml>");
        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            String key = entry.getKey();
            String value = entry.getValue();
            sf.append("<" + key + ">" + value + "</" + key + ">");
        }
        sf.append("</xml>");

        return sf.toString();
    }

    /**
     * XML格式字符串转换为Map
     *
     * @param strXML XML字符串
     * @return XML数据转换后的Map
     * @throws Exception
     */
    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            return null;
        }

    }

    /***
     * 微信提交
     * @paramrequest
     * @param paramsMap
     * @return
     */
    public static Map<String, String> WeixinPost(Map<String, String> paramsMap,String postUrl){
        // 生成随机数字符串
        String nonceStr = Md5.getRandomNumCode(5);
        // 组装请求数据
        paramsMap.put("appid", WeChat.appid);
        paramsMap.put("mch_id", WeChat.mch_id);
        paramsMap.put("nonce_str", nonceStr);
        // 获取签名
        String sign = "";
        try {
            sign = WeChat.getPayCustomSign(paramsMap, WeChat.paykey);
        } catch (Exception e) {
            System.out.println("生成请求签名失败");
        }
        paramsMap.put("sign", sign);
        // map 转 xml 字符串
        String paramsXml=WeChat.mapToXml(paramsMap);

        System.out.println(paramsXml+"最终请求字符串");
        // 发送订单请求
        String result = HttpRequest.sendPost(postUrl, paramsXml);
        System.out.println("接收信息----->"+result);
        // 将返回的 xml 转化成 map
        Map<String, String> resultMap = null;
        // 获取预支付交易会话标识
        String prepay_id = "";
        String mweb_url = "";
        if (result.indexOf("SUCCESS") != -1) {
            try {
                resultMap = WeChat.xmlToMap(result);
            } catch (Exception e) {
            }
        }

        return resultMap;
    }

    /***
     * 公众号支付
     * @param request
     * @param response
     * @param out_trade_no
     * @param total_fee
     * @param attach
     * @param body
     * @return
     */
    public static String downOrderJSAPI(HttpServletRequest request, HttpServletResponse response, String out_trade_no, String total_fee, String attach, String body, String openid) {
        // 获取终端 IP
        String spbill_create_ip = UserRequest.getIp(request);
        //交易类型
        String TRADE_TYPE = "JSAPI";
        // 组装请求数据
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("body", body);
        paramsMap.put("attach", attach);
        paramsMap.put("out_trade_no", out_trade_no);
        paramsMap.put("total_fee", total_fee);
        paramsMap.put("spbill_create_ip", spbill_create_ip);
        paramsMap.put("notify_url", WeChat.NOTIFY_URL);
        paramsMap.put("trade_type", TRADE_TYPE);
        paramsMap.put("openid", openid);

        // 获取预支付交易会话标识
        String prepay_id = "";
        String mweb_url = "";
        String nonce_str="";
        //paramsMap=formatUrlMap(paramsMap,false,false);
        Map<String, String> resultMap = WeixinPost(paramsMap,WeChat.DOWN_ORDER);
        if (resultMap != null) {
            prepay_id = resultMap.get("prepay_id");
            if(prepay_id!=null) {
                System.out.println("ces");
                //设置订单支付信息
                PayOrder payOrder = new PayOrder();
                payOrder.setAttach(attach);
                payOrder.setNonceStr(nonce_str);
                payOrder.setTotal_fee(total_fee);
                payOrder.setOrderState("701");
                WeChat.orderData.put(out_trade_no, payOrder);
                return prepay_id;
            }
            else{
                return null;
            }
        } else {
            //返回解析失败
            System.out.println("下单失败js");
            return "{\"msgCode\":\"111111\",\"errorDetail\":\"下单失败\"}";
        }
    }

    /***
     * H5支付
     * @param request
     * @param response
     * @param out_trade_no
     * @param total_fee
     * @param attach
     * @param body
     * @return
     */
    public static String downOrderH5(HttpServletRequest request, HttpServletResponse response, String out_trade_no, String total_fee, String attach, String body) throws IOException, ServletException {
        System.out.println("H5");
        // 获取终端 IP
        String spbill_create_ip = UserRequest.getIp(request);
        //交易类型
        String TRADE_TYPE = "MWEB";
        //场景信息
        String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \""+WeChat.siteSurl+"\",\"wap_name\": \""+WeChat.siteName+"\"}}";
        scene_info = HttpRequest.getUTF8XMLString(scene_info);
        // 组装请求数据
        Map<String, String> paramsMap;
        paramsMap = new HashMap<>();
        paramsMap.put("body", body);
        paramsMap.put("attach", attach);
        paramsMap.put("out_trade_no", out_trade_no);
        paramsMap.put("total_fee", total_fee);
        paramsMap.put("spbill_create_ip", spbill_create_ip);
        paramsMap.put("notify_url", WeChat.NOTIFY_URL);
        paramsMap.put("trade_type", TRADE_TYPE);
        paramsMap.put("scene_info", scene_info);

        // 获取预支付交易会话标识
        String prepay_id = "";
        String mweb_url = "";
        String nonce_str="";

        Map<String, String> resultMap = WeixinPost(paramsMap,WeChat.DOWN_ORDER);
        if (resultMap != null) {
            prepay_id = resultMap.get("prepay_id");
            mweb_url = resultMap.get("mweb_url");
            nonce_str = resultMap.get("nonce_str");
            //设置订单支付信息
            PayOrder payOrder = new PayOrder();
            payOrder.setAttach(attach);
            payOrder.setNonceStr(nonce_str);
            payOrder.setTotal_fee(total_fee);
            payOrder.setOrderState("0");
            WeChat.orderData.put(out_trade_no,payOrder);
            mweb_url=mweb_url+"&redirect_url=";
            String url="http://www.ycsqd.com/API/Weixin/H5Callback";
            mweb_url=mweb_url+URLEncoder.encode(url,"utf-8");
            return "{\"msgCode\":\"2\",\"detail\":\""+mweb_url+"\"}";
        } else {
            //返回解析失败
            System.out.println("下单失败h5");
            return "{\"msgCode\":\"-2\",\"detail\":\"下单失败\"}";
        }
    }





    /***
     * 查询订单
     * @param out_trade_no
     * @param total_fee
     * @return
     */
    public static boolean getOrder(String out_trade_no,String total_fee) throws Exception {
        System.out.println("查询订单");
        boolean bl = false;
        // 组装请求数据
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("out_trade_no", out_trade_no);
        Map<String, String> resultMap = WeixinPost(paramsMap,WeChat.ORDER_URL);
        if (resultMap != null) {
            String out_trade_no1 = resultMap.get("out_trade_no");
            System.out.println("订单编号1--->" + out_trade_no1);
            String total_fee1 = resultMap.get("total_fee");
            System.out.println("sss:"+total_fee);
            //total_fee1=AmountUtils.changeF2Y(total_fee1);
            System.out.println("订单金--->" + total_fee1);
            try {
                total_fee1=(Double.parseDouble(total_fee1)/100)+"";
            }catch (    Exception E){
                total_fee1="0";
            }
            String trade_state=resultMap.get("trade_state");
            if(trade_state.equals("SUCCESS")){
                //支付成功
                System.out.println("out_trade_no:"+out_trade_no+" 2:"+out_trade_no1+" total_fee:"+total_fee+" 2:"+total_fee1);
                double Dtotal_fee=-1;
                double Dtotal_fee1=-2;
                try {
                    Dtotal_fee=Double.parseDouble(total_fee);
                    Dtotal_fee1=Double.parseDouble(total_fee1);
                }catch (Exception e){}

                if (out_trade_no.equals(out_trade_no1) && Dtotal_fee==Dtotal_fee1) {
                    bl = true;
                }
            }
        }
        return bl;
    }



    /***
     * 查询账单信息
     * @param bill_date
     * @return
     */
    public static List<BillOrder> getBILL(String bill_date)
    {
        // 生成随机数字符串
        String nonceStr = Md5.getRandomNumCode(5);

        // 组装请求数据
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("appid", WeChat.appid);
        paramsMap.put("mch_id", WeChat.mch_id);
        paramsMap.put("nonce_str", nonceStr);
        paramsMap.put("bill_date", bill_date);
        paramsMap.put("bill_type", "SUCCESS");
        // 获取签名
        String sign = "";
        try {
            sign = WeChat.getPayCustomSign(paramsMap, WeChat.paykey);
        } catch (Exception e) {
            System.out.println("生成请求签名失败");
        }
        paramsMap.put("sign", sign);
        // map 转 xml 字符串
        String paramsXml = WeChat.mapToXml(paramsMap);

        System.out.println("发送查询账单请求"+paramsXml);

        // 发送订单请求
        List<BillOrder> resultOrder = HttpRequest.sendPostBillOrder(WeChat.BILL_URL, paramsXml);
        //String result = paramsXml;

        //解析格式


        System.out.println("查询返回"+resultOrder);

        return resultOrder;
    }


    /**
     *微信支付统一下单
     **/
    public Map<String,Object> unifiedOrder(String orderNo,Integer sumFee, Map<String,Object> map){
        System.out.println("微信支付统一下单");
        Map<String,Object> resultMap = null;
        try {
            WxPaySendData paySendData = new WxPaySendData();
            //构建微信支付请求参数集合
            paySendData.setAppId(WeChat.appid);
            paySendData.setAttach("微信订单支付:"+orderNo);
            paySendData.setBody("商品描述");
            paySendData.setMchId(WeChat.mch_id);
            paySendData.setNonceStr(WeChatUtils.getRandomStr(32));
            paySendData.setNotifyUrl(WeChat.NOTIFY_URL);
            paySendData.setDeviceInfo("WEB");
            paySendData.setOutTradeNo(orderNo);
            paySendData.setTotalFee(sumFee);
            paySendData.setTradeType("JSAPI");
            paySendData.setSpBillCreateIp((String) map.get("remoteIp"));
            paySendData.setOpenId((String) map.get("openId"));
            //将参数拼成map,生产签名
            SortedMap<String,Object> params = buildParamMap(paySendData);
            paySendData.setSign(WeChatUtils.getSign(params));
            //将请求参数对象转换成xml
            String reqXml = WeChatUtils.sendDataToXml(paySendData);
            //发送请求
            byte[] xmlData = reqXml.getBytes();
            URL url = new URL(WeChat.DOWN_ORDER);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.setRequestProperty("Content_Type","text/xml");
            urlConnection.setRequestProperty("Content-length",String.valueOf(xmlData.length));
            DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
            outputStream.write(xmlData);
            outputStream.flush();
            outputStream.close();
            resultMap = WeChatUtils.parseXml(urlConnection.getInputStream());
        } catch (Exception e) {
            System.out.println("微信支付统一下单异常");
        }
        return resultMap;
    }

        /**
         * 构建统一下单参数map 用于生成签名
         * @param data
         * @return SortedMap<String,Object>
         */

        private SortedMap<String,Object> buildParamMap(WxPaySendData data){
            SortedMap<String,Object> paramters = new TreeMap<String, Object>();
            if (null != data){
                if (StringUtils.isNotEmpty(data.getAppId())){
                    paramters.put("appid",data.getAppId());
                }
                if (StringUtils.isNotEmpty(data.getAttach())){
                    paramters.put("attach",data.getAttach());
                }
                if (StringUtils.isNotEmpty(data.getBody())){
                    paramters.put("body",data.getBody());
                }
                if (StringUtils.isNotEmpty(data.getDetail())){
                    paramters.put("detail",data.getDetail());
                }
                if (StringUtils.isNotEmpty(data.getDeviceInfo())){
                    paramters.put("device_info",data.getDeviceInfo());
                }
                if (StringUtils.isNotEmpty(data.getFeeType())){
                    paramters.put("fee_type",data.getFeeType());
                }
                if (StringUtils.isNotEmpty(data.getGoodsTag())){
                    paramters.put("goods_tag",data.getGoodsTag());
                }
                if (StringUtils.isNotEmpty(data.getLimitPay())){
                    paramters.put("limit_pay",data.getLimitPay());
                }
                if (StringUtils.isNotEmpty(data.getMchId())){
                    paramters.put("mch_id",data.getMchId());
                }
                if (StringUtils.isNotEmpty(data.getNonceStr())){
                    paramters.put("nonce_str",data.getNonceStr());
                }
                if (StringUtils.isNotEmpty(data.getNotifyUrl())){
                    paramters.put("notify_url",data.getNotifyUrl());
                }
                if (StringUtils.isNotEmpty(data.getOpenId())){
                    paramters.put("openid",data.getOpenId());
                }
                if (StringUtils.isNotEmpty(data.getOutTradeNo())){
                    paramters.put("out_trade_no",data.getOutTradeNo());
                }
                if (StringUtils.isNotEmpty(data.getSign())){
                    paramters.put("sign",data.getSign());
                }
                if (StringUtils.isNotEmpty(data.getSpBillCreateIp())){
                    paramters.put("spbill_create_ip",data.getSpBillCreateIp());
                }
                if (StringUtils.isNotEmpty(data.getTimeStart())){
                    paramters.put("time_start",data.getTimeStart());
                }
                if (StringUtils.isNotEmpty(data.getTimeExpire())){
                    paramters.put("time_expire",data.getTimeExpire());
                }
                if (StringUtils.isNotEmpty(data.getProductId())){
                    paramters.put("product_id",data.getProductId());
                }
                if (data.getTotalFee()>0){
                    paramters.put("total_fee",data.getTotalFee());
                }
                if (StringUtils.isNotEmpty(data.getTradeType())){
                    paramters.put("trade_type",data.getTradeType());
                }
                //申请退款参数
                if (StringUtils.isNotEmpty(data.getTransactionId())){
                    paramters.put("transaction_id",data.getTransactionId());
                }
                if (StringUtils.isNotEmpty(data.getOutRefundNo())){
                    paramters.put("out_refund_no",data.getOutRefundNo());
                }
                if (StringUtils.isNotEmpty(data.getOpUserId())){
                    paramters.put("op_user_id",data.getOpUserId());
                }
                if (StringUtils.isNotEmpty(data.getRefundFeeType())){
                    paramters.put("refund_fee_type",data.getRefundFeeType());
                }
                if (null != data.getRefundFee() && data.getRefundFee()>0){
                    paramters.put("refund_fee",data.getRefundFee());
                }
            }
            return paramters;
        }
    /**
     *
     * 方法用途: 对所有传入参数按照字段名的Unicode码从小到大排序（字典序），并且生成url参数串<br>
     * 实现步骤: <br>
     *
     * @param paraMap   要排序的Map对象
     * @param urlEncode   是否需要URLENCODE
     * @param keyToLower    是否需要将Key转换为全小写
     *            true:key转化成小写，false:不转化
     * @return
     */
    public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower)
    {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try
        {
            List<Map.Entry<String, String>> infoIds = new ArrayList<>(tmpMap.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
            Collections.sort(infoIds, Comparator.comparing(o -> (o.getKey())));
            // 构造URL 键值对的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds)
            {
                if (StringUtils.isNotBlank(item.getKey()))
                {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlEncode)
                    {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower)
                    {
                        buf.append(key.toLowerCase() + "=" + val);
                    } else
                    {
                        buf.append(key + "=" + val);
                    }
                    buf.append("&");
                }

            }
            buff = buf.toString();
            if (buff.isEmpty() == false)
            {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e)
        {
            return null;
        }
        return buff;
    }


}
